﻿using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Data.SqlClient;
using System.Collections.Generic;

using Builderator.Core.Action;
using Builderator.Core.Interfaces;

namespace Builderator.Core.Plugin
{
    public enum ExecutionResult { Success, Fail }

    public abstract class PluginBase : ActionBase, IDatabase, IPlugin
    {
        public VariableDictionary Variables
        {
            get;
            set;
        }

        public int ExitCode
        {
            get;
            set;
        }

        public bool Running = true;

        public PluginBase(string name, Guid type)
            : base(name, type)
        {
            this.ExitCode = 0;

            this.Variables = new VariableDictionary();
        }

        public ExecutionResult Execute()
        {
            if (this.Validate())
            {
                return this.Run();
            }

            return ExecutionResult.Fail;
        }

        public virtual ExecutionResult Run()
        {
            while (this.Running) { Thread.Sleep(500); }

            return (this.ExitCode == 1) ? ExecutionResult.Fail : ExecutionResult.Success;
        }

        public virtual bool Validate()
        {
            try
            {
                this.ResolveVariables();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private void ResolveVariables()
        {
            foreach (Variable variable in this.Variables)
            {
                if (variable.Value.Contains("{") && variable.Value.Contains("}"))
                {
                    string name;
                    int index1, index2;
                    Variable related;

                    index1 = variable.Value.IndexOf("{");

                    index2 = variable.Value.IndexOf("}");

                    name = variable.Value.Substring(index1 + 1, index2 - 1);

                    related = this.Variables.Find(name);

                    variable.Value = variable.Value.Replace("{" + name + "}", related.Value);
                }
            }

            foreach (PropertyInfo property in this.GetType().GetProperties())
            {
                if (property.GetCustomAttributes(typeof(DocumentProperty), true).Length == 0)
                    continue;

                if (property.PropertyType != typeof(String))
                    continue;

                string value = (string)property.GetValue(this, null);

                if (value.Contains("{") && value.Contains("}"))
                {
                    string name;
                    int index1, index2;
                    Variable related;

                    index1 = value.IndexOf("{");

                    index2 = value.IndexOf("}");

                    name = value.Substring(index1 + 1, index2 - 1);

                    related = this.Variables.Find(name);

                    value = value.Replace("{" + name + "}", related.Value);

                    property.SetValue(this, value, null);
                }
            }
        }

        public void DebugMessage(StreamReader reader)
        {
            new Thread(new ThreadStart(delegate
                {
                    this.Debug(reader);
                })).Start();
        }

        private void Debug(StreamReader reader)
        {
            while (!reader.EndOfStream)
            {
                this.DebugMessage(reader.ReadLine());
            }
        }

        public override string Select(DatabaseTable table)
        {
            switch (table)
            {
                case DatabaseTable.Actions:
                    return base.Select(table);
                case DatabaseTable.Plugins:
                    return string.Format("SELECT * FROM plugins WHERE identifier='{0}'", this.Type.ToString());
                default:
                    return string.Empty;
            }
        }

        public override string Insert(DatabaseTable table)
        {
            switch (table)
            {
                case DatabaseTable.Actions:
                    return base.Insert(table);
                case DatabaseTable.Plugins:
                    return string.Format("INSERT INTO plugins VALUES ('{0}', '{1}')", this.Type, this.GetType().FullName);
                default:
                    return string.Empty;
            }
        }

        public override string Delete(DatabaseTable table)
        {
            switch (table)
            {
                case DatabaseTable.Actions:
                    return base.Delete(table);
                case DatabaseTable.Plugins:
                    return string.Format("DELETE FROM plugins WHERE identifier='{0}'", this.Type.ToString());
                default:
                    return string.Empty;
            }
        }
    }
}